#pragma once
#include "../OutputFile.hpp"
#include "../../Library/BigEndianNumber.hpp"
namespace Level1
{
	class OutputJavaFile :
		public OutputFile
	{
#pragma pack(push, 1)
		class HeaderPart1
		{
		public:
			unsigned magic;
			static const unsigned magicNumber = 0xBEBAFECA;
			static const unsigned short majorVersionJava17 = 61;
			static const unsigned short minorVersionJava17 = 0;
			BigEndianUnsignedShort minorVersion, majorVersion, constantPoolCount;
		};
		class ConstantInformation
		{
		public:
			enum class Type : unsigned char
			{
				CONSTANT_Utf8 = 1,
				CONSTANT_Integer = 3,
				CONSTANT_Float = 4,
				CONSTANT_Long = 5,
				CONSTANT_Double = 6,
				CONSTANT_Class = 7,
				CONSTANT_String = 8,
				CONSTANT_Fieldref = 9,
				CONSTANT_Methodref = 10,
				CONSTANT_InterfaceMethodref = 11,
				CONSTANT_NameAndType = 12,
				CONSTANT_MethodHandle = 15,
				CONSTANT_MethodType = 16,
				CONSTANT_Dynamic = 17,
				CONSTANT_InvokeDynamic = 18,
				CONSTANT_Module = 19,
				CONSTANT_Package = 20
			}tag;
		};
		class ConstantInformationString final :
			public ConstantInformation
		{
		public:
			BigEndianUnsignedShort index;
		};
		using ConstantInformationClass = ConstantInformationString;
		using ConstantInformationModule = ConstantInformationString;
		using ConstantInformationMethodType = ConstantInformationString;
		using ConstantInformationPackage = ConstantInformationString;
		class ConstantInformationField :
			public ConstantInformation
		{
		public:
			BigEndianUnsignedShort classIndex, nameAndTypeIndex;
		};
		using ConstantInformationMethod = ConstantInformationField;
		using ConstantInformationInterface = ConstantInformationField;
		using ConstantInformationNameAndType = ConstantInformationField;
		using ConstantInformationInvokeDynamic = ConstantInformationField;
		using ConstantInformationDynamic = ConstantInformationField;
		class ConstantInformationInteger :
			public ConstantInformation
		{
		public:
			BigEndianUnsignedInteger value;
		};
		using ConstantInformationFloat = ConstantInformationInteger;
		class ConstantInformationLong :
			public ConstantInformation
		{
		public:
			BigEndianUnsignedLong value;
		};
		using ConstantInformationDouble = ConstantInformationLong;
		class ConstantInformationUTF8 :
			public ConstantInformation
		{
		public:
			BigEndianUnsignedShort length;
			unsigned char str[];
			static unsigned __int64 BuildString(const std::u32string& str, ConstantInformationUTF8* ptr);
		};
		class ConstantInformationMethodHandle :
			ConstantInformation
		{
		public:
			enum class ReferencrKind : unsigned char
			{
				GetField = 1,//getfield C.f:T
				GetStatic = 2,//getstatic C.f : T
				PutField = 3,//putfield C.f : T
				PutStatic = 4,//putstatic C.f : T
				InvokeVirtual = 5,//invokevirtual C.m : (A*)T
				InvokeStatic = 6,//invokestatic C.m : (A*)T
				InvokeSpecial = 7,//invokespecial C.m : (A*)T
				NewInvokeSpecial = 8,//new C; dup; invokespecial C.<init>:(A*)V
				InvokeInterface = 9
			}referenceKind;
			BigEndianUnsignedShort referenceIndex;
		};
		class HeaderPart2
		{
		public:
			class AccessFlags
			{
			public:
				unsigned short : 1;                // 0x0001
				unsigned short interfaceFlag : 1;  // 0x0002
				unsigned short abstractFlag : 1;   // 0x0004
				unsigned short : 1;                // 0x0008
				unsigned short syntheticFlag : 1;  // 0x0010
				unsigned short annotationFlag : 1; // 0x0020
				unsigned short enumFlag : 1;       // 0x0040
				unsigned short moduleFlag : 1;     // 0x0080
				unsigned short publicFlag : 1;     // 0x0100
				unsigned short : 3;                // 0x0200 ~ 0x0800
				unsigned short finalFlag : 1;      // 0x1000
				unsigned short superFlag : 1;      // 0x2000
				unsigned short : 2;                // 0x4000 ~ 0x8000
			}accessFlag;
			BigEndianUnsignedShort thisClass, superClass, interfacesCount, interfaces[];
		};
		class HeaderPart3
		{
		public:
			BigEndianUnsignedShort fieldsCount, fields[];
		};
#pragma pack(pop)
	};
}